#!/bin/bash -
#===============================================================================
#
#          FILE: lamp.sh
#
#         USAGE: ./lamp.sh
#
#   DESCRIPTION: 
#
#       OPTIONS: ---
#  REQUIREMENTS: ---
#          BUGS: ---
#         NOTES: ---
#        AUTHOR: zimingzpp (zhang), zimingzpp@qq.com
#  ORGANIZATION: 
#       CREATED: 09/09/20 13:10:37
#      REVISION:  ---
#===============================================================================

set -o nounset                                  # Treat unset variables as an error
set -e


#-------------------------------------------------------------------------------
#设置环境变量 
#-------------------------------------------------------------------------------
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

cur_dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P)

#-------------------------------------------------------------------------------
#red 
#-------------------------------------------------------------------------------
_red(){
    printf '\033[1;31;31m%b\033[0m' "$1" 
}

#-------------------------------------------------------------------------------
#green 
#-------------------------------------------------------------------------------
_green(){
    printf '\033[1;31;32m%b\033[0m' "$1" 
}

#-------------------------------------------------------------------------------
#yellow 
#-------------------------------------------------------------------------------
_yellow(){
    printf '\033[1;31;33m%b\033[0m' "$1" 
}

#-------------------------------------------------------------------------------
#_error函数:显示错误信息 
#-------------------------------------------------------------------------------
_error(){
    _red "$1"
    printf "\n"
    exit 1
}

#-------------------------------------------------------------------------------
#_printargs函数：标准化输出
#-------------------------------------------------------------------------------
_printargs(){
    printf -- "%s" "$1"
    printf "\n"
}

#-------------------------------------------------------------------------------
#info函数: 标准化输出信息 
#-------------------------------------------------------------------------------
_info(){
    _printargs "$@"
}


#-------------------------------------------------------------------------------
#is_digit函数:判断是否为数字 
#-------------------------------------------------------------------------------
is_digit(){
    local input="$1"
    if [[ "$input" =~ ^[0-9]+$ ]]; then
        return 0
    else
        return 1
    fi
}


#-------------------------------------------------------------------------------
#get_valid_valname函数: 将变量中的"-" "."符号替换成"_" 
#-------------------------------------------------------------------------------
get_valid_valname(){
    local val="$1"
    local new_val=$(eval echo $val| sed 's/[-.]/_/g')
    echo $new_val
}

#-------------------------------------------------------------------------------
#get_hint函数 
#-------------------------------------------------------------------------------
get_hint(){
    local val="$1"
    local new_val=$(get_valid_valname $val)
    eval echo "\$hint_${new_val}"
}

#-------------------------------------------------------------------------------
#set-hint函数:  
#-------------------------------------------------------------------------------
set_hint(){
    local val="$1"
    local hint="$2"
    local new_val=$(get_valid_valname $val)
    eval hint_${new_val}="\$hint"
}

#-------------------------------------------------------------------------------
#Include函数：引用需要的脚本 
#-------------------------------------------------------------------------------
include(){
    local src=${1}
    if [[ -s ${cur_dir}/include/${src}.sh ]] ; then
        . ${cur_dir}/include/$src.sh
    else
        echo "Error: ${cur_dir}/include/$src.sh not found, or shell cannot be executed!"
        exit
    fi
}

#-------------------------------------------------------------------------------
#check_sys函数: 检测系统类型 
#-------------------------------------------------------------------------------
check_sys(){
    local checkType="$1"
    local value="$2"
    local release=""
    local systemPackage=""
    
    if [ -f /etc/redhat-release ] ; then
        release="centos"
        systemPackage="yum"
    elif grep -Eqi "centos|red hat|redhat" /etc/issue; then
        release="centos"
        systemPackage="yum"
    elif grep -Eqi "debian" /etc/issue; then
        release="debian"
        systemPackage="apt"
    elif grep -Eqi "ubuntu" /etc/issue; then
        release="ubuntu"
        systemPackage="apt"
    elif grep -Eqi "centos|red hat|redhat" /proc/version; then
        release="centos"
        systemPackage="yum"
    elif grep -Eqi "debian" /proc/version; then
        release="debian"
        systemPackage="apt"
    elif grep -Eqi "ubuntu" /proc/version; then
        release="ubuntu"
        systemPackage="apt"
    fi
    if [ "$checkType" == "sysRelease" ]; then
        if [ "$release" == "$value" ]; then
            return 0
        else
            return 1
        fi
    elif [ "$checkType" == "packageManager" ]; then
        if [ "$systemPackage" == "$value" ]; then
            return 0
        else
            return 1
        fi
    fi
}

#-------------------------------------------------------------------------------
#versionget函数: 
#-------------------------------------------------------------------------------
versionget(){
    if [[ -s /etc/redhat-release ]]; then
        grep -oE "[0-9.]+" /etc/redhat-release
    else
        grep -oE "[0-9.]+" /etc/issue
    fi
}

#-------------------------------------------------------------------------------
#get_centosversion函数: 获取centos具体版本号
#-------------------------------------------------------------------------------
get_centosversion(){
    if check_sys sysRelease centos; then
        local version=$(versionget)
        #${version%%.*}:删除第一个"."及其右边的内容
        echo ${version%%.*}
    else
        echo ""
    fi
}

#-------------------------------------------------------------------------------
#get_os_release函数:  
#-------------------------------------------------------------------------------
get_os_release(){
    #{print ($1,$3~/^[0-9]/?$3:$4)}暂时不懂
    [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return
    [ -f /etc/os-release ] && awk -F'[="]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return
    [ -f /etc/lsb-release ] && awk -F'[="]+' '/PRETTY_NAME/{print $2}' /etc/lsb-release && return
}




#-------------------------------------------------------------------------------
#get_debianversion函数: 获取debian的版本 
#-------------------------------------------------------------------------------
get_debianversion(){
    if check_sys sysRelease debian; then
        local version=$(get_os_release)
        local main_version=$(echo $version| grep -oE "[0-9.]+")
        echo ${main_version%%.*}
    else
        echo ""
    fi
}

#-------------------------------------------------------------------------------
#get_ubuntuversion函数: 获取ubuntu的版本 
#-------------------------------------------------------------------------------
get_ubuntuversion(){
    if check_sys sysRelease ubuntu; then
        local version=$(get_os_release)
        local main_version=$(echo $version| grep -oE "[0-9.]+")
        echo ${main_version%%.*}
    else
        echo ""
    fi
}

#-------------------------------------------------------------------------------
#check_os函数: 检测系统 
#-------------------------------------------------------------------------------
check_os(){
    is_support_flg=0
    if check_sys packageManager yum || check_sys packageManager apt; then
        if [ -n "$(get_centosversion)" ] && [ "$(get_centosversion)" -lt 6 ]; then
            is_support_flg=1
        fi
        if [ -n "$(get_ubuntuversion)" ] && [ "$(get_ubuntuversion)" -lt 14 ]; then
            is_support_flg=1
        fi
        if [ -n "$(get_debianversion)" ] && [ "$(get_debianversion)" -lt 8 ]; then
            is_support_flg=1
        fi
    else
        is_support_flg=1
    fi
    if [ $is_support_flg -eq 1 ]; then
        _error "系统不支持，请在centos 6+或debian 8+或Ubuntu 14+系统上运行!"
        exit 1
    fi
}

#-------------------------------------------------------------------------------
#get_os_info函数:获取系统信息 
#-------------------------------------------------------------------------------
get_os_info(){
    cname=$( awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
    cores=$( awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo )
    freq=$( awk -F: '/cpu MHz/ {freq=$2} END {print freq}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' )
    tram=$( free -m | awk '/Mem/ {print $2}' )
    swap=$( free -m | awk '/Swap/ {print $2}' )
    up=$( awk '{a=$1/86400;b=($1%86400)/3600;c=($1%3600)/60;d=$1%60} {printf("%ddays, %d:%d:%d\n",a,b,c,d)}' /proc/uptime )
    load=$( w | head -1 | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//' )
    opsy=$( get_os_release )
    arch=$( uname -m )
    lbit=$( getconf LONG_BIT )
    host=$( hostname )
    kern=$( uname -r )
    ramsum=$( expr $tram + $swap )
}

#-------------------------------------------------------------------------------
#check_ram函数:  
#-------------------------------------------------------------------------------
check_ram(){
    get_os_info
    if [ ${ramsum} -lt 480 ]; then
        _error "内存不够，安装LAMP需要内存: ${tram}MB*RAM + ${swap}MB*SWAP >= 480MB"
    fi
    [ ${ramsum} -lt 1025 ] && disable_fileinfo="--disable_fileinfo" || disable_fileinfo=""
}

#-------------------------------------------------------------------------------
#get_ip函数:获取IP地址 
#-------------------------------------------------------------------------------
get_ip(){
    local ipv4=$(ip addr| egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'| egrep -v '^169|\.255$|^0\.|^127'|head -n 1)
    printf -- "%s" "${ipv4}"
}

#-------------------------------------------------------------------------------
#version_lt 
#-------------------------------------------------------------------------------
version_lt(){
    test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"
}

#-------------------------------------------------------------------------------
#get_libc_version
#-------------------------------------------------------------------------------
get_libc_version(){
    getconf -a |grep GUN_LIBC_VERSION | awk '{print $NF}'
}


#-------------------------------------------------------------------------------
#display_os_info函数: 显示系统配置信息 
#-------------------------------------------------------------------------------
display_os_info(){
    clear
    echo
    echo "+-------------------------------------------------------------------+"
    echo "| 自动化安装LAMP脚本(Linux + Apache + MySQL/MariaDB + PHP )         |"
    echo "| 网址 : gitee.com/zimingzpp/lamp                                   |"
    echo "| 作者 : zimingzpp <zimingzpp@qq.com>                               |"
    echo "+-------------------------------------------------------------------+"
    echo
    echo "----------------------------- 系统信息 ------------------------------"
    echo
    echo "CPU型号                   : ${cname}"
    echo "核芯数                    : ${cores}"
    echo "CPU主频                   : ${freq} MHz"
    echo "内存                      : ${tram} MB"
    echo "SWAP                      : ${swap} MB"
    echo "系统启动时间              : ${up}"
    echo "Load average              : ${load}"
    echo "系统                      : ${opsy}"
    echo "架构                      : ${arch} (${lbit} Bit)"
    echo "内核                      : ${kern}"
    echo "主机名                    : ${host}"
    echo "IPv4地址                  : $(get_ip)"
    echo
    echo "---------------------------------------------------------------------"
}

#-------------------------------------------------------------------------------
#lamp_preinstall函数: lamp预安装啊，选择需要安装的选项 
#-------------------------------------------------------------------------------
lamp_preinstall(){
    apache_preinstall_settings
    mysql_preinstall_settings
#    php_preinstall_settings
#    php_modules_preinstall_settings
#    phpmyadmin_preinstall_settings
#    kodexplorer_preinstall_settings
}

#-------------------------------------------------------------------------------
#apache_preinstall_settings函数
#-------------------------------------------------------------------------------
apache_preinstall_settings(){
    display_menu apache 1
    echo ${apache}
    if [ "$apache" == "do_not_install" ]; then
        apache_modules_install="do_not_install"
    else
        display_menu_multi apache_modules last
    fi
}

#-------------------------------------------------------------------------------
#mysql_preinstall_settings函数
#-------------------------------------------------------------------------------
mysql_preinstall_settings(){
    if version_lt $(get_libc_version) 2.14; then
        mysql_arr=(${mysql_arr[@]#${mariadb10_3_filename}})
        mysql_arr=(${mysql_arr[@]#${mariadb10_4_filename}})
        mysql_arr=(${mysql_arr[@]#${mariadb10_5_filename}})
    fi
    display_menu mysql 2
    if [ "${mysql}" != "do_not_install" ];then
        if echo "${mysql}" | grep -qi "mysql"; then
            #mysql data
            echo
            read -p "mysql data location(default:${mysql_location}/data, leave blank for default): " mysql_data_location
            mysql_data_location=${mysql_data_location:=${mysql_location}/data}
            mysql_data_location=$(filter_location "${mysql_data_location}")
            echo
            echo "mysql data location: ${mysql_data_location}"

            #set mysql server root password
            echo
            read -p "mysql server root password (default:lamp.sh, leave blank for default): " mysql_root_pass
            mysql_root_pass=${mysql_root_pass:=lamp.sh}
            echo
            echo "mysql server root password: ${mysql_root_pass}"

        elif echo "${mysql}" | grep -qi "mariadb"; then
            #mariadb data
            echo
            read -p "mariadb data location(default:${mariadb_location}/data, leave blank for default): " mariadb_data_location
            mariadb_data_location=${mariadb_data_location:=${mariadb_location}/data}
            mariadb_data_location=$(filter_location "${mariadb_data_location}")
            echo
            echo "mariadb data location: ${mariadb_data_location}"

            #set mariadb server root password
            echo
            read -p "mariadb server root password (default:lamp.sh, leave blank for default): " mariadb_root_pass
            mariadb_root_pass=${mariadb_root_pass:=lamp.sh}
            echo
            echo "mariadb server root password: $mariadb_root_pass"

        fi
    fi
}

#-------------------------------------------------------------------------------
#display_menu函数 
#-------------------------------------------------------------------------------
display_menu(){
    local software="$1"
    local default_choice="$2"
    eval local arr=(\${${software}_arr[@]})
    local default_prompt
    if [[ "$default_choice" != "" ]]; then
        if [[ "$default_choice" == last ]]; then
            default_choice=${#arr[@]}
        fi
        default_prompt="(默认为: ${arr[${default_choice}-1]})"
    fi
    local pick
    local hint
#    local vname
    local prompt="你想安装哪一版${software}?  ${default_prompt}:"

    while true; do
        echo -e "\n---------------------------- ${software}设置 -----------------------------\n"
        for (( i = 1; i <= ${#arr[@]}; i++ )); do
#            vname="$(get_valid_valname ${arr[$i-1]})"
#            hint="$(get_hint $vname)"
#            [[ "$hint" == "" ]] && hint="${arr[$i-1]}"
            hint="${arr[${i}-1]}"
            _info "$(_green $i). $hint"
        done
        echo
        read -p "$prompt" pick
        if [[ "$pick" == "" && "${default_choice}" != "" ]]; then
            pick=${default_choice}
            break
        fi
        if ! is_digit "$pick"; then
            prompt="Input error, please only input a number:"
            continue
        fi
        if [[ "$pick" -lt 1 || "$pick" -gt ${#arr[@]} ]]; then
            prompt="Input error, please input a number between 1 and ${#arr[@]}:"
            continue
        fi
        break
    done
    eval $software=${arr[${pick}-1]}
#    vname="$(get_valid_valname ${arr[${pick}-1]})"
#    hint="$(get_hint $vname)"
#    [[ "$hint" == "" ]] && hint="${arr[${pick}-1]}"
    hint="${arr[${pick}-1]}"
    echo -e "\nyour selection: $hint"
}

#-------------------------------------------------------------------------------
#display_menu_multi函数:  
#-------------------------------------------------------------------------------
display_menu_multi(){
    local software="$1"
    local default_choice="$2"
    eval local arr=(\${${software}_arr[@]})
    local arr_len=${#arr[@]}
    local picko
    local correct=true
    local prompt
    local vane
    local hint
    local default_prompt
    if [[ "$default_choice" != "" ]]; then
        if [[ "$default_choice" == "last" ]]; then
            default_choice=${arr_len}
        fi
        default_prompt="(默认选项: ${arr[${default_choice}-1]})"
    fi
    prompt="请输入1到${arr_len}之间的数字${default_prompt}:"
    echo -e "\n---------------------------- ${software}设置 -----------------------------\n"
    for (( i = 1; i <= ${arr_len}; i++ )); do
        hint=${arr[${i}-1]}
        _info "$(_green ${i}). $hint"
    done
    echo
    while true; do
        read -p "$prompt" pick
        #pick=(${pick})
        eval unset ${software}_install
        if [[ "$pick" == "" ]]; then
            if [[ "$default_choice" == "" ]]; then
                echo "输入不能为空, 请重新输入:"
                continue
            else
                eval ${software}_install="${arr[${default_choice}-1]}"
                break
            fi
        fi
        for j in ${pick[@]}; do
            if ! is_digit "$j"; then
                echo "输入错误，请输入数字:"
                correct=false
                break 1
            fi
            if [[ "$j" -lt 1 || "$j" -gt "${arr_len}" ]]; then
                echo "输入错误, 请输入1到${arr_len}之间的数字："
                correct=false
                break 1
            fi
            if [[ "$arr[$j-1]" == "do_not_install" ]]; then
                eval ${software}_install="do_not_install"
                break 2
            fi
#            eval ${software}_install="\"\${software}_install ${arr[$j-1]}\""
            eval ${software}_install="\"\${${software}_install[@]} ${arr[${j}-1]}\""
            correct=true
        done
        [[ "$correct" == "true" ]] && break
    done

    echo
    eval echo -e "your selection: \$${software}_install"
}



#-------------------------------------------------------------------------------
#last_confirm函数: 最后安装前确认 
#-------------------------------------------------------------------------------
#last_confirm(){ }

#-------------------------------------------------------------------------------
#start_install函数: 
#-------------------------------------------------------------------------------
#start_install(){ }

#-------------------------------------------------------------------------------
#lamp_install函数:开始源码编译安装lamp 
#-------------------------------------------------------------------------------
#lamp_install(){ }





#-------------------------------------------------------------------------------
#pre_setting函数：脚本安装前环境检查 
#-------------------------------------------------------------------------------
pre_setting(){
    check_os
    check_ram
    display_os_info
    lamp_preinstall
#    last_confirm
#    start_install
#    lamp_install
}



#-------------------------------------------------------------------------------
#Main函数 
#-------------------------------------------------------------------------------
main(){
    pre_setting
}

include config
load_config

#-------------------------------------------------------------------------------
#执行脚本 
#-------------------------------------------------------------------------------
 main
